﻿#region File Description
//-----------------------------------------------------------------------------
// Enemy.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Media;

namespace Platformer
{
    /// <summary>
    /// Facing direction along the X axis.
    /// 
    /// </summary>
    enum FaceDirection
    {
        Left = -1,
        Right = 1,
    }

    /// <summary>
    /// A monster who is impeding the progress of our fearless adventurer.
    /// </summary>
    class Enemy
    {
        public Level Level
        {
            get { return level; }
        }
        Level level;

        /// <summary>
        /// Position in world space of the bottom center of this enemy.
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
        }
        Vector2 position;

        // Enemy die
        public bool Alive
        {
            get { return alive; }
            set { alive = value; }
        }
        bool alive;

        //Enemy Types
        public string Type
        {
            get { return type; }
            set { type = value; }
        }
        string type;

        // Enemy HP
        public int Health
        {
            get { return hp; }
            set { hp = value; }
        }
        int hp;

        // Enemy damage
        public int Damage
        {
            get { return damage; }
            set { damage = value; }
        }
        int damage;

        // Enemy Points System
        public int Points
        {
            get { return points; }
            set { points = value; }
        }
        int points;

        private Rectangle localBounds;
        /// <summary>
        /// Gets a rectangle which bounds this enemy in world space.
        /// </summary>
        public Rectangle BoundingRectangle
        {
            get
            {
                int left = (int)Math.Round(Position.X - sprite.Origin.X) + localBounds.X;
                int top = (int)Math.Round(Position.Y - sprite.Origin.Y) + localBounds.Y;

                return new Rectangle(left, top, localBounds.Width, localBounds.Height);
            }
        }


        // Animations
        private Animation runAnimation;
        private Animation idleAnimation;
        private Animation frozenAnimation;
        private Animation bossCastAnimation;
        private AnimationPlayer sprite;

        public Texture2D boss;

        private double timeFrozen = 1000;
        private bool checkFrozen;
        private double delay = 400, slow = 400, pause = 1000, deleteTime = 400;
        private double intervalTime = 0; // time in current interval
        private double previousIntervalTime = 0; // interval time at last frame
        //fireball 
        public List<Fireball> fireBall = new List<Fireball>();

        public List<FlamePath> flamePath = new List<FlamePath>();

        public List<PurpleFireball> skull = new List<PurpleFireball>();
        /// <summary>
        /// The direction this enemy is facing and moving along the X axis.
        /// </summary>
        public FaceDirection direction = FaceDirection.Left;

        /// <summary>
        /// How long this enemy has been waiting before turning around.
        /// </summary>
        private float waitTime;

        /// <summary>
        /// How long to wait before turning around.
        /// </summary>
        private const float MaxWaitTime = 0.5f;

        /// <summary>
        /// The speed at which this enemy moves along the X axis.
        /// </summary>
        private float MoveSpeed = 64.0f;

        /// <summary>
        /// Constructs a new Enemy.
        /// </summary>
        public Enemy(Level level, Vector2 position, string spriteSet, string typ, int hp, int points, int damage)
        {
            this.level = level;
            this.position = position;
            /// Module:             Games Programming
            /// Assignment1:        Platformer XNA Starter Kit
            /// Add game feature:   Enemy features
            /// Student Name:       Teo Zhi Wei Elvin
            /// Student Number:     S10077131J
            /// Class:              3T02
            this.alive = true;
            this.type = typ;
            this.hp = hp;
            this.damage = damage;
            this.points = points;

            LoadContent(spriteSet);
        }

        /// <summary>
        /// Loads a particular enemy sprite sheet and sounds.
        /// </summary>
        public void LoadContent(string spriteSet)
        {
            // Load animations.
            spriteSet = "Sprites/" + spriteSet + "/";
            runAnimation = new Animation(Level.Content.Load<Texture2D>(spriteSet + "Run"), 0.1f, true);
            idleAnimation = new Animation(Level.Content.Load<Texture2D>(spriteSet + "Idle"), 0.15f, true);
            frozenAnimation = new Animation(Level.Content.Load<Texture2D>(spriteSet + "Frozen"), 1.0f, true);
            sprite.PlayAnimation(idleAnimation);

            // Calculate bounds within texture size.
            int width = (int)(idleAnimation.FrameWidth * 0.35);
            int left = (idleAnimation.FrameWidth - width) / 2 + 15;
            int height = (int)(idleAnimation.FrameWidth * 0.7);
            int top = idleAnimation.FrameHeight - height;
            localBounds = new Rectangle(left, top, width, height);
        }


        /// <summary>
        /// Paces back and forth along a platform, waiting at either end.
        /// </summary>
        public void Update(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // Calculate tile position based on the side we are walking towards.
            float posX = Position.X + localBounds.Width / 2 * (int)direction;
            int tileX = (int)Math.Floor(posX / Tile.Width) - (int)direction;
            int tileY = (int)Math.Floor(Position.Y / Tile.Height);

            if (waitTime > 0)
            {
                // Wait for some amount of time.
                waitTime = Math.Max(0.0f, waitTime - (float)gameTime.ElapsedGameTime.TotalSeconds);
                if (waitTime <= 0.0f)
                {
                    // Then turn around.
                    direction = (FaceDirection)(-(int)direction);
                }
            }
            else
            {
                // If we are about to run into a wall or off a cliff, start waiting.
                if (Level.GetCollision(tileX + (int)direction, tileY - 1) == TileCollision.Impassable ||
                    Level.GetCollision(tileX + (int)direction, tileY) == TileCollision.Passable)
                {
                    waitTime = MaxWaitTime;
                }
                else
                {
                    // Module:             Games Programming
                    // Assignment1:        Platformer XNA Starter Kit
                    // Add game feature:   Enemy features
                    // Student Name:       Teo Zhi Wei Elvin
                    // Student Number:     S10077131J
                    // Class:              3T02
                    // Monster that has high movement speed
                    if (type == "Fast")
                    {
                        if (!checkFrozen)
                        {
                            MoveSpeed = 300.0f;
                            Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
                            position = position + velocity;
                        }
                    }

                    // Module:             Games Programming
                    // Assignment1:        Platformer XNA Starter Kit
                    // Add game feature:   Enemy features
                    // Student Name:       Teo Zhi Wei Elvin
                    // Student Number:     S10077131J
                    // Class:              3T02
                    // Monster that chase player
                    else if (type == "Chase")
                    {
                        if (!checkFrozen)
                        {
                            ChasePlayer(gameTime);
                            Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
                            position = position + velocity;
                        }
                    }
                    // Module:             Games Programming
                    // Assignment1:        Platformer XNA Starter Kit
                    // Add game feature:   Enemy features
                    // Student Name:       Jerald
                    // Student Number:     S10076342F
                    // Class:              3T02
                    // Monster that fires fireballs at player
                    else if (type == "Fire")
                    {
                        if (!checkFrozen)
                        {
                            BossChasePlayer(gameTime);
                            if (Timer(gameTime))
                            {
                                int dir;
                                MoveSpeed = 0.0f;
                                Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
                                if (direction == FaceDirection.Left)
                                    dir = -1;
                                else
                                    dir = 1;
                                fireBall.Add(new Fireball(level, new Vector2(position.X - 3, position.Y - 5), dir));
                            }
                        }

                    }
                    else if (type == "Boss")
                    {
                        if (!checkFrozen)
                        {
                            BossChasePlayer(gameTime);
                            int dir;
                            MoveSpeed = 48.0f;
                            Vector2 velocity = new Vector2((int)direction * MoveSpeed * elapsed, 0.0f);
                            position = position + velocity;
                            if (direction == FaceDirection.Left)
                                dir = -1;
                            else
                                dir = 1;
                            if (Timer(gameTime))
                                skull.Add(new PurpleFireball(level, new Vector2(position.X - 3, position.Y - 5), dir));

                            if (slow <= 0)
                            {

                                flamePath.Add(new FlamePath(level, new Vector2(position.X - 3, position.Y - 5), dir));
                                slow = 200;
                            }
                            else
                                slow -= (double)gameTime.ElapsedGameTime.Milliseconds;
                        }
                    }
                }
            }

            foreach (Fireball fireballs in fireBall)
                fireballs.UpdateFireball();
            foreach (FlamePath flamePaths in flamePath)
                flamePaths.UpdateFlamePath();
            foreach (PurpleFireball pSkull in skull)
                pSkull.UpdatePurpleFireball();

            for (int i = 0; i < fireBall.Count(); i++)
            {
                Fireball fire = fireBall.ElementAt(i);
                if (fire.collided == true)
                {
                    if (delay <= 0)
                    {
                        fireBall.RemoveAt(i);
                        delay = 300;
                    }
                    else
                        delay -= (double)gameTime.ElapsedGameTime.Milliseconds;
                }
            }

            for (int i = 0; i < flamePath.Count(); i++)
            {
                FlamePath flame = flamePath.ElementAt(i);
                if (pause <= 0)
                {
                    flamePath.RemoveAt(i);
                    pause = 2000;
                }
                else
                    pause -= (double)gameTime.ElapsedGameTime.Milliseconds;
            }

            for (int i = 0; i < skull.Count(); i++)
            {
                PurpleFireball purple = skull.ElementAt(i);
                if (purple.collided == true)
                {
                    if (deleteTime <= 0)
                    {
                        skull.RemoveAt(i);
                        deleteTime = 300;
                    }
                    else
                        deleteTime -= (double)gameTime.ElapsedGameTime.Milliseconds;
                }
            }

            if (checkFrozen)
            {

                if (timeFrozen <= 0)
                    unfreezeEnemy();
                else
                    timeFrozen -= (double)gameTime.ElapsedGameTime.Milliseconds;
            }
        }

        /// <summary>
        /// Draws the animated enemy.
        /// </summary>
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            SpriteEffects flip = new SpriteEffects();

            // Stop running when the game is paused or before turning around.
            if (!Level.Player.IsAlive ||
                Level.ReachedExit ||
                Level.TimeRemaining == TimeSpan.Zero ||
                waitTime > 0)
            {
                sprite.PlayAnimation(idleAnimation);
            }
            else
            {
                sprite.PlayAnimation(runAnimation);
            }

            if (checkFrozen)
            {
                sprite.PlayAnimation(frozenAnimation);
                flip = direction > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
            }

            // Draw facing the way the enemy is moving.
            if (!checkFrozen)
                flip = direction > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None;

            sprite.Draw(gameTime, spriteBatch, Position, flip);

            foreach (Fireball fireballs in fireBall)
                fireballs.Draw(gameTime, spriteBatch);
            foreach (FlamePath flamePaths in flamePath)
                flamePaths.Draw(gameTime, spriteBatch);
            foreach (PurpleFireball pSkull in skull)
                pSkull.Draw(gameTime, spriteBatch);
        }

        //Chase player function
        public void ChasePlayer(GameTime gameTime)
        {
            if (Level.Player.Position.Y == position.Y && (Math.Abs(Level.Player.Position.X - position.X)) <= Tile.Width * 3)
            {
                if (Level.Player.Position.X > position.X)
                {
                    direction = FaceDirection.Right;
                }
                else if (Level.Player.Position.X < position.X)
                {
                    direction = FaceDirection.Left;
                }
            }
        }

        public void BossChasePlayer(GameTime gameTime)
        {
            if (Level.Player.Position.Y == position.Y && (Math.Abs(Level.Player.Position.X - position.X)) <= Tile.Width * 100)
            {
                if (Level.Player.Position.X > position.X)
                {
                    direction = FaceDirection.Right;
                }
                else if (Level.Player.Position.X < position.X)
                {
                    direction = FaceDirection.Left;
                }
            }
        }

        public bool Timer(GameTime gameTime)
        {
            bool resetInterval = false;

            // add time lapse between frames and keep value between 0 & 1000 ms
            intervalTime += (double)gameTime.ElapsedGameTime.Milliseconds;
            intervalTime = intervalTime % 2000;

            // intervalTime has been reset so a new interval has started
            if (intervalTime < previousIntervalTime)
                resetInterval = true;

            previousIntervalTime = intervalTime;

            return resetInterval;
        }

        public void freezeEnemy(int i)
        {
            checkFrozen = true;
            MoveSpeed = 0.0f;

            sprite.PlayAnimation(frozenAnimation);
            timeFrozen = i;
        }

        public void unfreezeEnemy()
        {
            checkFrozen = false;
            MoveSpeed = 64.0f;
            sprite.PlayAnimation(runAnimation);
        }

    }
}
